#include "key_drv.h"
#include "systick.h"
#include "led_drv.h"

static Key_Info_t g_keyInfo[KEY_NUM_MAX];
static uint8_t g_keyVal;

/**
 * @brief 按键硬件初始化
 * @param
 * @return
 */
void KeyDrvInit(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.GPIO_Pin = g_gpioList[0].pin;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD; /* 下拉输入 */
    GPIO_Init(g_gpioList[0].gpio, &GPIO_InitStruct);

    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; /* 上拉输入 */

    for (uint8_t i = 1; i < KEY_NUM_MAX; i++)
    {
        GPIO_InitStruct.GPIO_Pin = g_gpioList[i].pin;
        GPIO_Init(g_gpioList[i].gpio, &GPIO_InitStruct);
    }
}

/**
 * @brief 判断按键是否按下
 * @param _id 按键编号
 * @return 返回值：1 表示按下，0 表示未按下
 */
static uint8_t IsKeyPress(uint8_t _id)
{
    return (GPIO_ReadInputDataBit(g_gpioList[_id].gpio, g_gpioList[_id].pin) == g_gpioList[_id].ActiveLevel);
}

/**
 * @brief 按键扫描
 * @param keyIndex 按键编号
 */
static void KeyScan(uint8_t keyIndex)
{
    volatile uint64_t curSysTime;
    uint8_t keyPress;

    keyPress = IsKeyPress(keyIndex);

    switch (g_keyInfo[keyIndex].keyState)
    {
    case KEY_RELEASE: /* 释放状态，判断有无按键按下 */
        if (keyPress) /* 按键按下 */
        {
            g_keyInfo[keyIndex].keyState = KEY_CONFIRM;
            g_keyInfo[keyIndex].firstIoChangeSysTime = GetSysRunTime();
            break;
        }
        if (g_keyInfo[keyIndex].singleClickNum != 0)
        {
            curSysTime = GetSysRunTime();
            if (curSysTime - g_keyInfo[keyIndex].firstIoChangeSysTime > DOUBLE_CLICK_INTERVAL_TIME)
            {
                g_keyInfo[keyIndex].singleClickNum = 0;
                g_keyVal = keyIndex + 0x01; /* 返回单击按键码值，三个按键短按对应0x01, 0x02, 0x03 */
                return;
            }
        }
        break;

    case KEY_CONFIRM: /* 消抖状态 */
        if (keyPress) /* 按键按下 */
        {
            curSysTime = GetSysRunTime();
            if (curSysTime - g_keyInfo[keyIndex].firstIoChangeSysTime > CONFIRM_TIME)
            {
                g_keyInfo[keyIndex].keyState = KEY_SHORTPRESS;
            }
        }
        else
        {
            g_keyInfo[keyIndex].keyState = KEY_RELEASE;
        }
        break;

    case KEY_SHORTPRESS: /* 短按状态：继续判定是短按，还是双击，还是长按 */
        if (keyPress)    /* 按键按下 */
        {
            curSysTime = GetSysRunTime();
            if (curSysTime - g_keyInfo[keyIndex].firstIoChangeSysTime > LONGPRESS_TIME) /* 超过长按时间间隔 */
            {
                g_keyInfo[keyIndex].keyState = KEY_LONGPRESS;
            }
        }
        else
        {
            g_keyInfo[keyIndex].keyState = KEY_RELEASE;

            g_keyInfo[keyIndex].singleClickNum++;
            if (g_keyInfo[keyIndex].singleClickNum == 1)
            {
                g_keyInfo[keyIndex].firstReleaseSysTime = GetSysRunTime();
                break;
            }
            else
            {
                curSysTime = GetSysRunTime();
                if (curSysTime - g_keyInfo[keyIndex].firstReleaseSysTime <= DOUBLE_CLICK_INTERVAL_TIME) /* 超过双击时间间隔，返回双击码值 */
                {
                    g_keyInfo[keyIndex].singleClickNum = 0;
                    g_keyVal = keyIndex + 0x51; /* 返回按键码值，三个按键双击对应0x51, 0x52, 0x53 */
                    return;
                }
            }
        }
        break;

    case KEY_LONGPRESS: /* 长按状态 */
        if (!keyPress)  /* 按键释放 */
        {
            g_keyInfo[keyIndex].keyState = KEY_RELEASE;
            g_keyVal = keyIndex + 0x81; /* 返回按键码值，三个按键长按对应0x81, 0x82, 0x83 */
            return;
        }
        break;

    default:
        g_keyInfo[keyIndex].keyState = KEY_RELEASE;
        break;
    }
}

/**
 * @brief 扫描所有按键。非阻塞，被systick中断周期性的调用
 * @param
 */
void KeyScanTask(void)
{
    for (uint8_t i = 0; i < KEY_NUM_MAX; i++)
    {
        KeyScan(i);
    }
}

/**
 * @brief 获取按键码值
 * @param
 * @return 四个按键码值，短按0x01 0x02 0x03
 *                      双击0x51 0x52 0x53
 *                      长按0x81 0x82 0x83
 *                      没有按下为0
 */
uint8_t GetKeyVal(void)
{
    return g_keyVal;
}

/**
 * @brief 按键测试
 * @param
 */
void KeyDrvTest(void)
{
    uint8_t keyVal = GetKeyVal();
    switch (keyVal)
    {
    case KEY1_SHORT_PRESS:
        // printf("key1 short press\n");
        LedDrvSet(LED0, ENABLE);
        LedDrvSet(LED1, DISABLE);
        break;
    case KEY1_DOUBLE_PRESS:
        LedDrvSet(LED0, ENABLE);
        LedDrvSet(LED1, DISABLE);
        // printf("key1 double press\n");
        break;
    case KEY1_LONG_PRESS:
        LedDrvSet(LED0, ENABLE);
        LedDrvSet(LED1, DISABLE);
        // printf("key1 long press\n");
        break;
    case KEY2_SHORT_PRESS:
        LedDrvSet(LED1, ENABLE);
        LedDrvSet(LED0, DISABLE);
        // printf("key2 short press\n");
        break;
    case KEY2_DOUBLE_PRESS:
        LedDrvSet(LED1, ENABLE);
        LedDrvSet(LED0, DISABLE);
        // printf("key2 double press\n");
        break;
    case KEY2_LONG_PRESS:
        LedDrvSet(LED1, ENABLE);
        LedDrvSet(LED0, DISABLE);
        // printf("key2 long press\n");
        break;
    case KEY3_SHORT_PRESS:
        LedDrvSet(LED0, ENABLE);
        LedDrvSet(LED1, ENABLE);
        // printf("key3 short press\n");
        break;
    case KEY3_DOUBLE_PRESS:
        LedDrvSet(LED0, ENABLE);
        LedDrvSet(LED1, ENABLE);
        // printf("key3 double press\n");
        break;
    case KEY3_LONG_PRESS:
        LedDrvSet(LED0, ENABLE);
        LedDrvSet(LED1, ENABLE);
        // printf("key3 long press\n");
        break;
    default:
        break;
    }
}
